package com.wmd.core.operation;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Consts;
import org.apache.http.HeaderElement;
import org.apache.http.HeaderElementIterator;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustAllStrategy;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContexts;
import org.springframework.util.StringUtils;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;

/**
 * @projectName:susiBim
 * @packageName:com.wmd.susi.util
 * @Description:线程池请求http工具类
 * @Author:luyincheng
 * @CreateDate: 2022/7/714:39
 */
@Slf4j
public class PoolingHttpClient4 {

    private static final CloseableHttpClient httpClient;
    private static final BasicResponseHandler responseHandler;
    private static final RequestConfig requestConfig;
    private static final PoolingHttpClientConnectionManager connectionManager;

    static {
//        System.setProperty("http.maxConnections","50");
//        System.setProperty("http.keepAlive", "true");
        SSLContext sslContext = null;
        try {
            sslContext = SSLContexts.custom().loadTrustMaterial(null,new TrustAllStrategy()).build();
        } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
           log.error(e.getMessage());
           sslContext=SSLContexts.createDefault();
        }
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,  new NoopHostnameVerifier());
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
                .register("https", sslsf)
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .build();
        connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        connectionManager.setMaxTotal(500);
        connectionManager.setDefaultMaxPerRoute(50);//例如默认每路由最高50并发，具体依据业务来定
        connectionManager.setValidateAfterInactivity(2000);
        //创建http客户端
        httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                //KeyStore.getInstance(KeyStore.getDefaultType())
//                .setSSLContext(SSLContexts.custom().loadTrustMaterial(null,new TrustAllStrategy()).build())
//                .setSSLSocketFactory(SSLConnectionSocketFactory.getSocketFactory())
                .setKeepAliveStrategy((response,context)-> {
                    HeaderElementIterator it = new BasicHeaderElementIterator
                            (response.headerIterator(HTTP.CONN_KEEP_ALIVE));
                    while (it.hasNext()) {
                        HeaderElement he = it.nextElement();
                        String param = he.getName();
                        String value = he.getValue();
                        if (value != null && param.equalsIgnoreCase
                                ("timeout")) {
                            return Long.parseLong(value) * 1000;
                        }
                    }
                    return 10 * 1000;//如果没有约定，则默认定义时长为10s
                })
//                .setDefaultRequestConfig(RequestConfig.custom().setStaleConnectionCheckEnabled(true).build())
//                .useSystemProperties()
                .setRetryHandler(new DefaultHttpRequestRetryHandler(5,true))
                .build();


        //初始化HTTP请求配置
        requestConfig=RequestConfig.custom()
                .setContentCompressionEnabled(true)
                .setSocketTimeout(6000)
                .setAuthenticationEnabled(true)
                .setConnectionRequestTimeout(3500)
                .setConnectTimeout(3500).build();
//        httpPost.addHeader(HEADER_CONTENT_TYPE, "application/json");
//        httpPost.addHeader("token", TOKEN);
//        httpPost.addHeader("source", SOURCE);
        //初始化response解析器
        responseHandler = new BasicResponseHandler();
    }
    public static final String HEADER_CONTENT_TYPE="Content-Type";
    public static String doPost(String url,Map<String,String> headers,Map<String,String> params, JSONObject jsonParam){

        if(params!=null&& !params.isEmpty()){
            StringBuilder stringBuilder=new StringBuilder();
            params.forEach((k,v)-> {
                    stringBuilder.append("&").append(k).append("=").append(StringUtils.hasLength(v)?v:"null");
            });
            stringBuilder.deleteCharAt(0);
            url+="?"+stringBuilder.toString();
        }
        log.info(url);


        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig( requestConfig);
//        httpPost.addHeader(HEADER_CONTENT_TYPE, "application/json");
        if(headers!=null){
            headers.forEach(httpPost::addHeader);
        }
        String contentType=null;
        if(headers!=null&& headers.containsKey(HEADER_CONTENT_TYPE)){
            contentType=headers.get(HEADER_CONTENT_TYPE);
        }else{
            contentType=ContentType.APPLICATION_JSON.getMimeType();
        }
        try {
            String paramString=jsonParam!=null?jsonParam.toJSONString():"";
            log.debug(paramString);
            if(ContentType.APPLICATION_FORM_URLENCODED.getMimeType().equals(contentType)){
                httpPost.addHeader(HEADER_CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.getMimeType());

                StringBuilder jsonStringBuilder=new StringBuilder();
                if(jsonParam!=null&& !jsonParam.isEmpty()){
                    jsonParam.forEach((k,v)->jsonStringBuilder.append("&").append(k).append("=").append(v));
                    jsonStringBuilder.deleteCharAt(0);
                    httpPost.setEntity(new StringEntity(jsonStringBuilder.toString()));
//            url+=stringBuilder.toString();
                }
            }else{
                httpPost.addHeader(HEADER_CONTENT_TYPE, contentType);
                httpPost.setEntity(new StringEntity(paramString));
            }
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage());
        }
        return Execute(httpPost);
    }

    public static String doGet(String url,Map<String,String> headers,Map<String,String> params){

        if(params!=null&& !params.isEmpty()){
            StringBuilder stringBuilder=new StringBuilder();
            params.forEach((k,v)-> {
                    stringBuilder.append("&").append(k).append("=").append(StringUtils.hasLength(v)?v:"null");
            });
            stringBuilder.deleteCharAt(0);
            url+="?"+stringBuilder.toString();
        }
        log.info(url);
        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig( requestConfig);
        if(headers!=null){
            headers.forEach(httpGet::addHeader);
        }
        if(!httpGet.containsHeader(HEADER_CONTENT_TYPE)){
            httpGet.addHeader(HEADER_CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType());
        }
        return Execute(httpGet);

    }

    public static String Execute(HttpUriRequest postOrGet){
        try {
            String result = httpClient.execute(postOrGet,responseHandler);
            log.info(result);
            return result;
        } catch (IOException e) {
//            e.printStackTrace();
            log.error(e.getMessage());
            return null;
        }
    }
}
